"""
This view can be used with pipes or queues.
"""

import time
import random

import pygame
from pygame.locals import *

import multiproc
from vec2d import Vec2d


SCREEN_SIZE = 640,480

BLACK = Color('black')


class Sprite(object):
    
    size = 11,11
    image_green = None
    image_red = None
    
    def __init__(self, position, obj_id):
        self.obj_id = obj_id
        
        self.rect = Rect((0,0),self.size)
        self._position = Vec2d(0,0)
        
        if not self.image_green:
            self.image_green = pygame.surface.Surface(self.rect.size)
            self.image_green.fill(Color('green'))
            self.image_red = pygame.surface.Surface(self.rect.size)
            self.image_red.fill(Color('red'))
        self.image = self.image_green
        
        self.position = position
        self.hit = False
    
    @property
    def position(self):
        return self._position
    @position.setter
    def position(self, val):
        p = self._position
        p.x,p.y = val
        self.rect.center = round(p.x),round(p.y)
    
    @property
    def hit(self):
        return self._hit
    @hit.setter
    def hit(self, bool):
        self._hit = bool
        self.image = self.image_red if bool else self.image_green


class ViewQueueHandler(multiproc.QueueHandler):
    
    def msg_default(self, obj):
        self.runtime.log('ViewMsgHandler: unhandled: ' + str(obj))
    
    def msg_new_sprite(self, (obj_id,pos)):
        sprite = Sprite(pos, obj_id)
        self.runtime.sprites[obj_id] = sprite
    
    def msg_sprite_pos(self, data):
        sprites = self.runtime.sprites
        for (obj_id,pos,hit) in data:
            s = sprites[obj_id]
            s.position = pos
            s.hit = hit


class ViewRuntime(multiproc.Runtime):
    
    def _post_init(self):
        """This gets called by multiproc.MP.run. Remember: we're in a forked
        process now.
        """
        self.log('View: post init')
        pygame.init()
        self.screen = pygame.display.set_mode(SCREEN_SIZE)
        self.screen_rect = self.screen.get_rect()
        self.clock = pygame.time.Clock()
        
        self.put('model', ('screen_rect', self.screen_rect))
        
        self._caption_last_updated = 0
        self.sprites = {}
    
    def update(self):
        """This gets called by super.run
        """
        self.update_events()
        self.update_caption()
        self.draw()
    
    def update_caption(self):
        self.clock.tick()
        t = time.time()
        if t - self._caption_last_updated >= 1.0:
            pygame.display.set_caption('{0:.1f} fps | {1:d} sprites | {2:d} msgs/sec | Space:sprites C:collisions'.format(
                self.clock.get_fps(), len(self.sprites),
                self._queue_handlers['model'].msgs_in,
            ))
            self._queue_handlers['model'].msgs_in = 0
            self._caption_last_updated = t
    
    def draw(self):
        self.screen.fill(BLACK)
        blit = self.screen.blit
        sprites = self.sprites
        for obj_id in self.sprites:
            s = sprites[obj_id]
            blit(s.image, s.rect)
        pygame.display.flip()
    
    def update_events(self):
        for e in pygame.event.get():
            if e.type == KEYDOWN:
                self.on_key_down(e.key, e.mod)
            elif e.type == QUIT:
                self.on_quit()
    
    def on_key_down(self, key, mod):
        if key == K_SPACE:
            self.put('model', ('spawn_sprite', pygame.mouse.get_pos()))
        elif key == K_c:
            self.put('model', 'toggle_collisions')
        elif key == K_ESCAPE:
            self.running = False
    
    def on_quit(self):
        self.running = False
